#include<iostream>
#include<string>
#include"def.h"
#define ll unsigned long long
using namespace std;
char* buf;

string char2HEX(const unsigned char h[]) {
	string res = "";
	char list[] = "0123456789ABCDEF";
	for (int i = 0; i < 16; i += 4) {
		res += list[h[i] >> 4];		res += list[h[i] & 0xF];
		res += list[h[i + 1] >> 4];	res += list[h[i + 1] & 0xF];
		res += list[h[i + 2] >> 4];	res += list[h[i + 2] & 0xF];
		res += list[h[i + 3] >> 4];	res += list[h[i + 3] & 0xF];
		res += " ";
	}
	return res;
}
int main() {
	int choice;
	while (1) {
		cout << "0->退出\n1->输入字符串进行加密\n2->使用测试用例进行加密\n请输入选择:";
		cin >> choice;
		string s = "12345678901234567890123456789012345678901234567890123456789012345678901234567890";
		int num;
		if (choice == 0)return 0;
		else if (choice == 1) {
			cin.clear();
			cin.ignore();
			cout << "请输入加密字符串:";
			getline(cin, s);
		}
		else if (choice == 2) {
			cout << "请输入计算的样例编号(1~7):";
			cin >> num;
			num--;
			if (num < 0 | num>6) { cout << "输入有误！" << endl; continue; }
			s = tests[num].msg;
		}
		int len = s.length() << 3;//数据长度
		int groupNum = ((s.length() + 8) >> 6) + 1;//64字节的个数
		int fillNum = groupNum * 64 - s.length();//总需要填充的字节数(800000和数据长度)
		int firstPos = (s.length());
		for (int i = 0; i < fillNum; i++) {
			s += (unsigned char)0;
		}
		s[firstPos] = (unsigned char)0x80;
		memcpy(&s[(groupNum << 6) - 8], &len, 4);

		unsigned int A = 0x67452301;
		unsigned int B = 0xefcdab89;
		unsigned int C = 0x98badcfe;
		unsigned int D = 0x10325476;
		//分组循环
		unsigned int a, b, c, d;
		for (int i = 0; i < groupNum; i++) {//每一组都这样做
			a = A, b = B, c = C, d = D;
			for (int j = 0; j < 64; j++) {
				unsigned int f, m, temp;
				if (j < 16) {
					f = F(b, c, d);
					memcpy(&m, &s[((i) * 64) + (j << 2)], 4);
				}
				else if (j < 32)
				{
					f = G(b, c, d);
					memcpy(&m, &s[(i) * 64 + (((5 * j + 1) & 0xF) << 2)], 4);
				}
				else if (j < 48)
				{
					f = H(b, c, d);
					memcpy(&m, &s[(i) * 64 + (((3 * j + 5) & 0xF) << 2)], 4);
				}
				else {
					f = I(b, c, d);
					memcpy(&m, &s[(i) * 64 + (((7 * j) & 0xF) << 2)], 4);
				}
				//printf("\n第%d次循环：\na:%x, b:%x, c:%x, d:%x, F:%x, K:%x, M:%x, s:%x\n", j, a, b, c, d, f, K[j], m, S[j]);
				temp = b;
				b = b + shift(a + f + m + K[j], S[j]);
				a = d;
				d = c;
				c = temp;
			}
			A = (a + A);
			B = (b + B);
			C = (c + C);
			D = (d + D);
		}
		A = Small(A);
		B = Small(B);
		C = Small(C);
		D = Small(D);

		printf("MD5值为:%8X %8X %8X %8X\n", A, B, C, D);
		if (choice == 2) {
			printf("样例的MD5参考值为");
			cout << char2HEX(tests[num].hash) << endl;
		}
		cout << endl;
	}
}